/*
 * @Author: sjf 1758142861@qq.com
 * @Date: 2023-03-23 17:07:05
 * @LastEditors: sjf 1758142861@qq.com
 * @LastEditTime: 2023-03-23 17:58:56
 * @FilePath: /sjf/lwp/posix_sem/ring_queue.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <vector>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define NUM 8

namespace Anwtie
{
    template <class T>
    class RingQueue
    {
    public:
        RingQueue(int cap = NUM) : _cap(cap), _p_pos(0), _c_pos(0)
        {
            _q.resize(_cap);
            sem_init(&_block_sem, 0, _cap);
            sem_init(&_data_sem, 0, 0);
        }

        ~RingQueue()
        {
            sem_destroy(&_block_sem);
            sem_destroy(&_data_sem);
        }

        //对应的是生产者生产的数据
        void push(const T& data)
        {
            P(_block_sem);//保证该位置只能被生产者访问
            _q[_p_pos] = data;//插入生产者数据
            V(_data_sem);//释放wait消费者，让其可以访问

            _p_pos++;//生产者生产位置前进
            _p_pos %= _cap;//取模位置实现循环
        }

        //对应的是消费者拿到的数据
        void pop(T& data)
        {
            P(_data_sem);//保证该位置现在只能被消费者访问
            data = _q[_c_pos];//拿到_c_pos位置的数据
            V(_block_sem);//释放wait生产者，让该位置可以重新被访问

            _c_pos++;//消费者消费下一个位置
            _c_pos %= _cap;//取模位置实现循环
        }

    private:
        void P(sem_t &sem) { sem_wait(&sem); }//申请信号量
        void V(sem_t &sem) { sem_post(&sem); }//释放信号量

    private:
        std::vector<T> _q; // 环形队列
        int _cap;          // 环形队列的最大容量
        int _p_pos;        // 生产者下标
        int _c_pos;        // 消费者下标
        sem_t _block_sem;  // 生产者对应的空间
        sem_t _data_sem;   // 消费者对应的数据
    };
}